package client

import (
	"database/sql"
	"encoding/xml"
	"fmt"
	"gin-epg/internal/app/client/utils"
	"gin-epg/internal/app/common/util"
	"gin-epg/internal/app/dao"
	"gin-epg/internal/app/entity"
	"gin-epg/internal/app/model"
	"time"
)

// 频道名称映射
// 112114 有部分标准频道名不符合通常叫法， 卡通台 购物台 一般都不带省名 但是带省名和全程的同步快 不带的同步慢
var map112114 = map[string][]string{
	"江苏优漫卡通":  {"江苏优漫卡通", "优漫卡通"},
	"凤凰中文":    {"凤凰中文", "凤凰卫视中文台"},
	"凤凰资讯":    {"凤凰资讯", "凤凰卫视资讯台"},
	"凤凰香港":    {"凤凰香港", "凤凰卫视香港台"},
	"中国教育1台":  {"中国教育1台", "CETV1"},
	"中国教育2台":  {"中国教育2台", "CETV2"},
	"中国教育3台":  {"中国教育3台", "CETV3"},
	"中国教育4台":  {"中国教育4台", "CETV4"},
	"CHC高清电影": {"CHC高清电影", "CHC影迷电影"},
	"梨园":      {"梨园", "河南梨园"},
	"北京卫视":    {"北京卫视", "北京卫视4K"},
	// 更多键值对...
}

// 定义忽略列表
var ignoreList112114 = map[string]bool{
	"优漫卡通":    true,
	"凤凰卫视中文台": true,
	"凤凰卫视资讯台": true,
	"凤凰卫视香港台": true,
	"CETV1":   true,
	"CETV2":   true,
	"CETV3":   true,
	"CETV4":   true,
	"CHC影迷电影": true,
	"河南梨园":    true,
	// 添加更多需要忽略的频道
}

/*
 112114 原始域名https://epg.112114.xyz/pp.xml 这里使用镜像https://live.fanmingming.com/e.xml
 fanmingming 12.17加了cf 只能通过浏览器访问
 https://epg.112114.xyz
 https://epg.112114.eu.org
 http://diyp.112114.xyz
 https://epg.112114.xyz/pp.xml
 https://raw.githubusercontent.com/sparkssssssssss/epg/main/pp.xml
镜像
https://live.fanmingming.com/e.xml 加了cf无法直接访问
https://gitee.com/taksssss/tv/raw/main/epg/112114.xml 失效 现在只同步gz
*/
// 112114
func Handle112114Cron() error {
	dao.Logger.Infof("call task handle112114Cron")
	db := dao.SqlSession
	source := "112114"
	// 下载 112114 的 e.xml 这里用镜像
	// 主站  https://epg.112114.xyz/pp.xml
	// 备用1 https://diyp1000.112114.xyz/pp.xml 目前配置
	// 备用2 https://raw.githubusercontent.com/sparkssssssssss/epg/main/pp.xml
	// 备用3 https://live.fanmingming.com/e.xml 加了cf无法访问
	// 备用4 https://gitee.com/taksssss/tv/raw/main/epg/112114.xml.gz gz格式后续支持
	xmlURL := "http://diyp1000.112114.xyz/pp.xml"
	mirrorURL, err := util.GetConfigValue("mirror.mirror112114xml")
	if err != nil {
		dao.Logger.Errorf("Error: %v", err)
	} else {
		dao.Logger.Infof("mirrorURL mirror112114xml: %v", mirrorURL)
		xmlURL = fmt.Sprintf("%s", mirrorURL)
	}
	// 获取 XML 数据
	xmlData, err := utils.FetchXML(xmlURL)
	if err != nil {
		return fmt.Errorf("failed to fetch XML: %v", err)
	}

	// 解析 XML 数据
	var tv model.TV
	if err := xml.Unmarshal(xmlData, &tv); err != nil {
		return fmt.Errorf("failed to parse XML: %v", err)
	}

	// 构造频道id--频道名的map
	mapChannelIdName := utils.BuildChannelMap(&tv)

	// 按天按频道分组处理节目
	type ProgramKey struct {
		Date    string
		Channel string
	}
	programMap := make(map[ProgramKey][]*entity.EpgProgramCollect)

	for _, programme := range tv.Programmes {
		startDate := utils.FormatToDate(programme.Start)
		stopDate := utils.FormatToDate(programme.Stop)

		date := startDate.Format("2006-01-02")
		start := startDate.Format("15:04")
		stop := stopDate.Format("15:04")
		channel := mapChannelIdName[programme.Channel]
		title := programme.Title

		// 检查频道是否在忽略列表中
		if ignoreList112114[channel] {
			dao.Logger.Infof("Ignoring channel: %s", channel)
			continue
		}

		// 检查频道名称是否需要映射
		if mappedChannels, ok := map112114[channel]; ok {
			for _, mappedChannel := range mappedChannels {
				dateParsed, _ := time.Parse("2006-01-02", date)
				newEpc := &entity.EpgProgramCollect{
					Channel:    mappedChannel,
					Date:       entity.NullDate{sql.NullTime{Time: dateParsed, Valid: true}},
					Start:      start,
					End:        stop,
					Title:      title,
					Source:     source,
					CreateTime: entity.NullTime{sql.NullTime{Time: time.Now(), Valid: true}},
				}
				key := ProgramKey{Date: date, Channel: mappedChannel}
				programMap[key] = append(programMap[key], newEpc)
			}
		} else {
			dateParsed, _ := time.Parse("2006-01-02", date)
			newEpc := &entity.EpgProgramCollect{
				Channel:    channel,
				Date:       entity.NullDate{sql.NullTime{Time: dateParsed, Valid: true}},
				Start:      start,
				End:        stop,
				Title:      title,
				Source:     source,
				CreateTime: entity.NullTime{sql.NullTime{Time: time.Now(), Valid: true}},
			}
			key := ProgramKey{Date: date, Channel: channel}
			programMap[key] = append(programMap[key], newEpc)
		}
	}

	// 遍历每个频道和天，构造三个列表
	for key, programs := range programMap {
		// 获取当前日期范围内的已有节目记录，按频道和日期过滤，并指定source
		var existingRecords []entity.EpgProgramCollect
		dateParsed, _ := time.Parse("2006-01-02", key.Date)
		// 打印当前频道和当前日期
		dao.Logger.Infof("Processing channel %s on date %s", key.Channel, key.Date)
		if err := db.Where(&entity.EpgProgramCollect{Channel: key.Channel, Date: entity.NullDate{sql.NullTime{Time: dateParsed, Valid: true}}, Source: source}).Find(&existingRecords).Error; err != nil {
			return fmt.Errorf("failed to get existing records for %s on %s: %v", key.Channel, key.Date, err)
		}

		existingMap := make(map[string]*entity.EpgProgramCollect)
		for i := range existingRecords {
			existingMap[existingRecords[i].Start] = &existingRecords[i]
		}

		var newPrograms, updatePrograms, deletePrograms []entity.EpgProgramCollect

		for _, program := range programs {
			if existingRecord, ok := existingMap[program.Start]; ok {
				if existingRecord.Title != program.Title || existingRecord.End != program.End {
					existingRecord.Title = program.Title
					existingRecord.End = program.End
					existingRecord.UpdateTime = entity.NullTime{sql.NullTime{Time: time.Now(), Valid: true}}
					updatePrograms = append(updatePrograms, *existingRecord)
				}
				delete(existingMap, program.Start)
			} else {
				newPrograms = append(newPrograms, *program)
			}
		}

		// 处理需要删除的记录
		for _, record := range existingMap {
			deletePrograms = append(deletePrograms, *record)
		}

		// 执行数据库操作
		if len(updatePrograms) > 0 {
			for _, program := range updatePrograms {
				if err := db.Model(&program).Updates(entity.EpgProgramCollect{Title: program.Title, End: program.End, UpdateTime: program.UpdateTime}).Error; err != nil {
					dao.Logger.Errorf("update error: %v", err)
				} else {
					dao.Logger.Debugf("update success: %v", program)
				}
			}
		}

		if len(newPrograms) > 0 {
			for _, program := range newPrograms {
				if err := db.Create(&program).Error; err != nil {
					dao.Logger.Errorf("insert error: %v", err)
				} else {
					dao.Logger.Debugf("insert success: %v", program)
				}
			}
		}

		if len(deletePrograms) > 0 {
			for _, program := range deletePrograms {
				if err := db.Delete(&program).Error; err != nil {
					dao.Logger.Errorf("delete error: %v", err)
				} else {
					dao.Logger.Debugf("delete success: %v", program)
				}
			}
		}
	}

	return nil
}
